from django.shortcuts import render_to_response, get_object_or_404
from django.template import RequestContext
from django.utils import simplejson as json
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseServerError
from django.core.urlresolvers import reverse
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required
from pyceab.course.models import Course
from pyceab.plan.models import Plan, PlannedCourse
from pyceab.plan.forms import PlannedCourseForm, CourseSearchForm
from pyceab.plan.decorators import owner_required
from pyceab.student.models import Student
from pyceab.utils import get_plan_for_current_user

WEIGHTED_FIELDS = (
        'cse_a',
        'cse_b',
        'cse_c',
        'cse_d',
        'te_math',
        'te_sci',
        'te_engsci',
        'te_engdes',
        )

TEXT_FIELDS = (
        'department',
        'course_code',
        'full_name',
        )


@login_required
def plans_index(request):
    plan = get_plan_for_current_user(request)
    # this is a little inefficient
    return plan_detail(request, plan_id=plan.id)

@owner_required('plan_id', Plan)
def plan_detail(request, plan_id, object=None, is_pdf=False):
    from collections import defaultdict

    # now passed in by owner_required decorator
    # current_plan = get_object_or_404(Plan, id=plan_id)
    current_plan = object
    planned_courses = PlannedCourse.objects.filter(plan = current_plan).select_related(depth=1).order_by('term')
    planned_courses = list(planned_courses)

    def collect_into_term(memo, pc):
        term = pc.get_term_display()
        memo[term].append(pc)
        return memo

    # course_dict = reduce(collect_into_term, planned_courses, defaultdict(list))
    # terms = [{'term': t[0], 'courses': t[1]} for t in course_dict.items()]
    # terms.sort(key=lambda x: x['term'])

    errors = current_plan.get_errors()
    # errors = []
    context = {
                # 'plan': terms,
                'courses': planned_courses,
                'errors': errors,
                'plan_id': plan_id,
            }

    if is_pdf:
        return context
    else:
        return render_to_response(
            'plan/detail.html',
            context,
            context_instance = RequestContext(request))

@owner_required('plan_id', Plan)
def validate_plan(request, plan_id, object=None):
    #plan = get_object_or_404(Plan, id=plan_id)
    plan = object

    errors = plan.get_errors()

    return render_to_response(
            'plan/validation_results.html',
            {'errors': errors},
            context_instance=RequestContext(request))

@owner_required('plan_id', Plan)
def create_planned_course(request, plan_id, object=None):
    #plan = get_object_or_404(Plan, id=plan_id)
    plan = object
    form = PlannedCourseForm(request.POST)
    if form.is_valid():
        planned_course = form.save()
        if request.is_ajax():
            properties = {
                    'course_id': planned_course.course.id,
                    'term': planned_course.get_term_display(),
                    }
            return HttpResponse(json.dumps(properties))
        return HttpResponseRedirect(
                reverse(
                    'planned_course_detail', 
                    args=[plan_id, planned_course.id]))
    else:
        context = {
                'form': form,
                'plan': plan,
                }
        return render_to_response(
                'plan/new_planned_course.html',
                context,
                context_instance=RequestContext(request))


@owner_required('plan_id', Plan)
def planned_courses_index(request, plan_id, object=None):
    if request.method == 'POST':
        return create_planned_course(request, plan_id=plan_id)
    planned_courses = PlannedCourse.objects.filter(plan__id=plan_id)
    if request.is_ajax():
        return HttpRequest(json.dumps(planned_courses.values()))
    context = {'planned_courses': planned_courses}
    return render_to_response(
            'plan/planned_courses_index.html',
            context,
            context_instance=RequestContext(request))

@owner_required('plan_id', Plan)
def add_course_to_plan(request, plan_id, object=None):
    # FIXME: Figure out if this is really necessary.
    term_lookup = dict(
        zip(range(1,9), ('1A', '1B', '2A', '2B', '3A', '3B', '4A', '4B'))
    )

    term_id = int(request.POST['quickadd_term'])
    course_code = request.POST['quickadd_course']
    #plan = Plan.objects.get(id=plan_id)
    plan = object
    course = Course.objects.get(short_form=course_code)
    planned_course = PlannedCourse(plan=plan, course=course, term=term_id)
    planned_course.save()

    serializable_course = [ (k, str(v)) for k,v in course.__dict__.items() ]
    course_out = dict(serializable_course)
    course_out['cse'] = course.cse()
    resp = {
        'term': term_lookup[term_id],
        'planned_course_id': planned_course.id,
        'course': course_out,
    }

    json_resp = json.dumps(resp)
    #return HttpResponse(json_resp, mimetype="application/json")
    return render_to_response('plan/plan_row.html',
            {'c': planned_course,},
            context_instance = RequestContext(request))

@owner_required('plan_id', Plan)
def delete_planned_course(request, plan_id, planned_course_id, object=None):
    planned_course = get_object_or_404(PlannedCourse, id=planned_course_id)
    plan_id = planned_course.plan.id
    if request.method=='POST':
        if not planned_course.course.core_course:
            planned_course.delete()
        return HttpResponse()

# @owner_required('plan_id', Plan)
@login_required
def course_search(request):
    # plan = get_object_or_404(Plan, id=plan_id)
    plan = get_plan_for_current_user(request)
    form = CourseSearchForm()
    context = {
            'form': form,
            'plan': plan,
            }
    return render_to_response(
            'plan/course_search.html',
            context,
            context_instance=RequestContext(request))

@owner_required('plan_id', Plan)
def course_results(request, plan_id, object=None):
    # plan = get_object_or_404(Plan, id=plan_id)
    plan = object
    existing_courses = [course.id for course in plan.courses.all()]
    query_args = {}
    for field in request.GET:
        if field in TEXT_FIELDS and request.GET[field]:
            query_args[field.encode('utf8') + '__icontains'] = \
                request.GET[field].encode('utf8')
        elif field in WEIGHTED_FIELDS:
            query_args[field.encode('utf8') + '__gt'] = 0
    results = Course.objects.filter(**query_args).exclude(id__in=existing_courses).order_by('short_form')
    context = {
            'results': results,
            'plan': plan,
            }
    return render_to_response(
            'plan/course_results.html',
            context,
            context_instance=RequestContext(request))

def index(request):
    if request.user.is_authenticated():
        return HttpResponseRedirect(reverse('plans_index'))
    else:
        return HttpResponseRedirect(reverse('login'))

def pdf_report(request):
    import ho.pisa as pisa
    import cStringIO as StringIO
    from datetime import datetime
    from django.template.loader import render_to_string

    plan = get_plan_for_current_user(request)
    payload = plan_detail(request, plan_id=plan.id, is_pdf = True)

    payload['student'] = Student.objects.get(user = request.user)
    payload['date'] = datetime.now()
    file_data = render_to_string('plan/pdf.html', payload, RequestContext(request))
    myfile = StringIO.StringIO()
    pisa.CreatePDF(file_data, myfile)
    myfile.seek(0)
    response =  HttpResponse(myfile, mimetype='application/pdf')
    response['Content-Disposition'] = 'attachment; filename=planner.pdf'
    return response

